﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Net;
using System.Text;
using System.Windows.Forms;


namespace BridgeManager
{
    public partial class ManagerForm : Form
    {
        private BridgeManager manager = new BridgeManager();
        private List<BridgeInfo> bridgeList;

        private delegate void UpdateDeviceList(List<BridgeInfo> bridgeInfoList);
        private UpdateDeviceList UpdateDeviceHandler;

        private PortPairs portPairDict = new PortPairs();
        private AsyncSocketUDPServer udpServer;

        public ManagerForm()
        {
            InitializeComponent();

            /* 显示设备列表头信息 */
            listView_Content.HeaderStyle = ColumnHeaderStyle.Clickable;
            listView_Content.View = View.Details;
            listView_Content.Columns.Add("现有连接", 256, HorizontalAlignment.Left);
            listView_Content.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

            /* 隐藏选项卡头 */
            tabControl_Main.SizeMode = TabSizeMode.Fixed;
            tabControl_Main.ItemSize = new Size(0, 17);
            tabControl_Main.Appearance = TabAppearance.FlatButtons;

            /* 新增连接初始值 */
            radioButton_TCPClient.Select();

            textBox_DestIP.Text = "192.168.7.101";
            textBox_DestPort.Text = "8127";
            textBox_SrcPort.Text = "0";

            /* 设备列表 */
            bridgeList = new List<BridgeInfo>();

            /* 添加列表更新服务函数 */
            UpdateDeviceHandler = new UpdateDeviceList(UpdateDeviceListMethod);

            IPEndPoint localEP = new IPEndPoint(IPAddress.Loopback, 8001);
            udpServer = new AsyncSocketUDPServer(localEP);
            udpServer.DataReceived += UdpDataReceived;
            udpServer.Start();
        }

        private BridgeInfo GetInfo()
        {
            BridgeInfo bridgeInfo = new BridgeInfo();
            
            bridgeInfo.comAName = String.Empty;
            bridgeInfo.localPort = textBox_SrcPort.Text;

            bridgeInfo.remoteIP = textBox_DestIP.Text;
            bridgeInfo.remotePort = textBox_DestPort.Text;

            if (radioButton_UDP.Checked)
                bridgeInfo.workMode = WorkMode.UDP;
            else if (radioButton_TCPClient.Checked)
                bridgeInfo.workMode = WorkMode.TCPClient;
            else
                bridgeInfo.workMode = WorkMode.TCPServer;

            return bridgeInfo;
        }

        private void toolStripButton_Add_Click(object sender, EventArgs e)
        {
            tabControl_Main.SelectedIndex = 0;
            return;
        }

        private void button_OK_Click(object sender, EventArgs e)
        {
            BridgeInfo bridge = GetInfo();

            /* 添加串口对 */
            PortPair pair = portPairDict.CreatePortPair();
            bridge.comAName = pair.portA["realportname"];
            bridge.comBName = string.Format("CNCB{0}", pair.GetNum());

            /* 通知服务 */
            bridge.action = "add";
            byte[] data = Encoding.Default.GetBytes(JsonConvert.SerializeObject(bridge));
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 8002);
            udpServer.Send(data, endpoint);
        }

        private void tabControl_Main_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl_Main.SelectedTab.Name == "信息")
            {
                Console.WriteLine("changed\n");
            }
        }

        private void toolStripButtonScan_Click(object sender, EventArgs e)
        {
            BridgeInfo bridgeInfo = new BridgeInfo();
            bridgeInfo.action = "query";

            byte[] data = Encoding.Default.GetBytes(JsonConvert.SerializeObject(bridgeInfo));
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 8002);
            udpServer.Send(data, endpoint);
        }

        private void UdpDataReceived(object sender, AsyncSocketUDPEventArgs e)
        {
            string content = Encoding.UTF8.GetString(e._state.buffer, 0, e._state.length);
            StringReader sr = new StringReader(content);

            JsonSerializer serializer = new JsonSerializer();
            ResponseInfo respInfo = (ResponseInfo)serializer.Deserialize(new JsonTextReader(sr), typeof(ResponseInfo));
            if (respInfo.action == "query")
            {
                sr = new StringReader(respInfo.result);
                object obj = serializer.Deserialize(new JsonTextReader(sr), typeof(List<BridgeInfo>));
                List<BridgeInfo> bridgeList = obj as List<BridgeInfo>;
                if (bridgeList == null)
                    bridgeList = new List<BridgeInfo>();

                /* 更新成员 */
                List<BridgeInfo> infoList = new List<BridgeInfo>();
                for (int i = 0; i < bridgeList.Count; i++)
                {
                    BridgeInfo bridge = bridgeList[i];

                    string pairNum = bridge.comBName.Substring(4);
                    if (portPairDict.ContainsKey(pairNum))
                    {
                        PortPair portPair = portPairDict[pairNum];
                        if (portPair.portA.ContainsKey("realportname"))
                        {
                            bridge.comAName = portPair.portA["realportname"];
                            infoList.Add(bridge);
                        }
                    }
                }

                this.Invoke(UpdateDeviceHandler, infoList);
            }
            else if (respInfo.action == "remove")
            {
                sr = new StringReader(respInfo.result);
                RemoveRespInfo resp = (RemoveRespInfo)serializer.Deserialize(new JsonTextReader(sr), typeof(RemoveRespInfo));

                int comNum = int.Parse(resp.target.Substring(4));
                portPairDict.RemovePair(comNum);

                Console.WriteLine(respInfo.result);
            }
        }

        private void UpdateDeviceListMethod(List<BridgeInfo> infoList)
        {
            foreach (BridgeInfo bridge in infoList)
            {
                if (bridgeList.Contains(bridge))
                    continue;

                string content = bridge.comAName + " <--> " + bridge.remoteIP + ":" + bridge.remotePort;
                ListViewItem listItem = new ListViewItem(content);
                listView_Content.BeginUpdate();
                listView_Content.Items.Add(listItem);
                listView_Content.EndUpdate();

                bridgeList.Add(bridge);
            }
        }

        private void listView_Content_MouseClick(object sender, MouseEventArgs e)
        {
            tabControl_Main.SelectedIndex = 1;

            int selectCount = listView_Content.SelectedItems.Count;
            if (selectCount == 0)
                return;

            string selectedItemText = listView_Content.SelectedItems[0].Text;
            int idx = selectedItemText.IndexOf(' ');
            string comName = selectedItemText.Substring(0, idx);

            for (int i = 0; i < bridgeList.Count; i++) {
                BridgeInfo bridgeInfo = bridgeList[i];
                if (bridgeInfo.comAName == comName)
                {
                    label_infoComName.Text = bridgeInfo.comAName;
                    label_RemoteIP.Text = bridgeInfo.remoteIP;
                    label_RemotePort.Text = bridgeInfo.remotePort;
                    label_WorkMode.Text = bridgeInfo.workMode.ToString();
                }
            }
        }
        private void button_DeleteDevice_Click(object sender, EventArgs e)
        {
            ListViewItem focusedItem = listView_Content.FocusedItem;
            if (focusedItem != null)
            {
                int index = focusedItem.Index;
                listView_Content.Items.RemoveAt(index);
            }
            listView_Content.FocusedItem = null;

            string selectedComName = label_infoComName.Text;

            /* 判断串口是否正在被占用 */
            try
            {
                SerialPort serialPort = new SerialPort(selectedComName);
                serialPort.Open();
                serialPort.Close();
                serialPort.Dispose();
            }
            catch (Exception)
            {
                MessageBox.Show("串口正在被使用，请首先关闭占用串口程序");
                return;
            }

            /* 删除选中的设备 */
            for (int i = 0; i < bridgeList.Count; i++)
            {
                BridgeInfo bridgeInfo = bridgeList[i];
                if (bridgeInfo.comAName == selectedComName)
                {
                    bridgeInfo.action = "remove";
                    byte[] data = Encoding.Default.GetBytes(JsonConvert.SerializeObject(bridgeInfo));
                    IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 8002);
                    udpServer.Send(data, endpoint);

                    break;
                }
            }
        }

        private void listView_Content_MouseMove(object sender, MouseEventArgs e)
        {
            ListView _ListView = (ListView)sender;
            ListViewItem _OldItem = null;
            if (_ListView.Tag != null) _OldItem = (ListViewItem)_ListView.Tag;

            ListViewItem _Item = _ListView.GetItemAt(e.X, e.Y);
            if (_Item != null)
            {
                if (_OldItem != null && !_OldItem.Equals(_Item))
                {
                    foreach (ListViewItem.ListViewSubItem lvi in _OldItem.SubItems)
                    {
                        lvi.BackColor = _ListView.BackColor;
                    }
                }

                foreach (ListViewItem.ListViewSubItem lvi in _Item.SubItems)
                {
                    lvi.BackColor = ColorTranslator.FromHtml("#E5F3FF");
                }

                _ListView.Tag = _Item;
            }
            else
            {
                if (_OldItem != null && !_OldItem.BackColor.Equals(_ListView.BackColor)) _OldItem.BackColor = _ListView.BackColor;
            }
        }

        private void radioButton_UDP_CheckedChanged(object sender, EventArgs e)
        {
            textBox_SrcPort.Enabled = true;
            textBox_DestIP.Enabled = true;
            textBox_DestPort.Enabled = true;
        }

        private void radioButton_TCPClient_CheckedChanged(object sender, EventArgs e)
        {
            textBox_SrcPort.Enabled = false;
            textBox_DestIP.Enabled = true;
            textBox_DestPort.Enabled = true;
        }

        private void radioButton_TCPServer_CheckedChanged(object sender, EventArgs e)
        {
            textBox_SrcPort.Enabled = true;
            textBox_DestIP.Enabled = false;
            textBox_DestPort.Enabled = false;
        }
    }
}